package com.pa165.languageschoolservice.serviceImpl;

import com.pa165.languageschoolpersistence.DAO.CourseDAO;
import com.pa165.languageschoolpersistence.DAO.LectorDAO;
import com.pa165.languageschoolpersistence.DAO.LectureDAO;
import com.pa165.languageschoolpersistence.Exceptions.ServiceFailureException;
import com.pa165.languageschoolpersistence.entities.Course;
import com.pa165.languageschoolpersistence.entities.Lector;
import com.pa165.languageschoolpersistence.entities.Lecture;
import com.pa165.languageschoolpersistence.entities.Student;
import com.pa165.languageschoolservice.DTO.CourseDTO;
import com.pa165.languageschoolservice.DTO.LectorDTO;
import com.pa165.languageschoolservice.DTO.LectureDTO;
import com.pa165.languageschoolservice.DTO.StudentDTO;
import com.pa165.languageschoolservice.service.LectureService;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Tomas Hruby
 *
 * Basic implementation of service for lectures.
 */
@Service("lectureService")
public class LectureServiceImpl implements LectureService {

    @Resource(name = "lectureDAO")
    private LectureDAO lectureDao;
    @Resource(name = "courseDAO")
    private CourseDAO courseDao;
    @Resource(name = "lectorDAO")
    private LectorDAO lectorDao;
    @Autowired
    private Mapper mapper;

    public LectureDAO getLectureDao() {
        return lectureDao;
    }

    public void setLectureDao(LectureDAO lectureDao) {
        this.lectureDao = lectureDao;
    }

    public CourseDAO getCourseDao() {
        return courseDao;
    }

    public void setCourseDao(CourseDAO courseDao) {
        this.courseDao = courseDao;
    }

    public LectorDAO getLectorDao() {
        return lectorDao;
    }

    public void setLectorDao(LectorDAO lectorDao) {
        this.lectorDao = lectorDao;
    }

    public Mapper getMapper() {
        return mapper;
    }

    public void setMapper(Mapper mapper) {
        this.mapper = mapper;
    }

    /**
     * Adds lecture.
     *
     * @param lectureDTO input lecture
     * @return lecture added
     * @throws ServiceFailureException if any error occurs
     */
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    @Override
    public LectureDTO add(@Valid LectureDTO lectureDTO) throws ServiceFailureException {
        if (lectureDTO == null) {
            throw new IllegalArgumentException("lecture is null in  LectureServiceImpl.add ");
        }
        Lecture lecture = mapper.map(lectureDTO, Lecture.class);

        lectureDao.add(lecture);

        return mapper.map(lecture, LectureDTO.class);
    }

    /**
     * Removes lecture.
     *
     * @param lecture input lecture
     * @throws ServiceFailureException if any error occurs
     */
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    @Override
    public void remove(@Valid LectureDTO lecture) throws ServiceFailureException {
        if (lecture == null) {
            throw new IllegalArgumentException("lecture is null in  LectureServiceImpl.remove ");
        }
        Lecture toAdd = mapper.map(lecture, Lecture.class);

        lectureDao.remove(toAdd);
    }

    /**
     * Modifies lecture.
     *
     * @param lecture lecture to modify
     * @return modified lecture
     * @throws ServiceFailureException if any error occurs.
     */
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    @Override
    public LectureDTO modify(@Valid LectureDTO lecture) throws ServiceFailureException {
        if (lecture == null) {
            throw new IllegalArgumentException("lecture is null in  LectureServiceImpl.modify ");
        }
        Lecture toAdd = mapper.map(lecture, Lecture.class);
        lectureDao.modify(toAdd);

        return mapper.map(toAdd, LectureDTO.class);
    }

    /**
     * Gets lecture.
     *
     * @param id id of lecture
     * @return lecture requested
     * @throws ServiceFailureException if any error occurs.
     */
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_USER')")
    @Transactional(readOnly = true)
    @Override
    public LectureDTO get(Long id) throws ServiceFailureException {
        if (id == null) {
            throw new IllegalArgumentException("ID is null.");
        }

        Lecture result = lectureDao.get(id);

        return result == null ? null : mapper.map(result, LectureDTO.class);
    }

    /**
     * Gets all the lectures.
     *
     * @return List of lectures
     */
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_USER')")
    @Transactional(readOnly = true)
    @Override
    public List<LectureDTO> getAll() {
        List<Lecture> lectures = lectureDao.getAll();
        List<LectureDTO> result = new ArrayList<LectureDTO>();
        for (Lecture lecture : lectures) {
            result.add(mapper.map(lecture, LectureDTO.class));
        }

        return result;
    }

    /**
     * Gets lectures with the given lector.
     *
     * @param lector lector
     * @return lectures that are taught by lector
     * @throws ServiceFailureException if any error occurs.
     */
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_USER')")
    @Transactional(readOnly = true)
    @Override
    public List<LectureDTO> getLectures(LectorDTO lector) throws ServiceFailureException {
        if (lector == null) {
            throw new IllegalArgumentException("Lector is null in LectureServiceImpl.getLectures method");
        }
        Lector lectorEntity = mapper.map(lector, Lector.class);


        List<Lecture> lectures = lectureDao.getLectures(lectorEntity);
        List<LectureDTO> result = new ArrayList<LectureDTO>();
        for (Lecture lecture : lectures) {
            result.add(mapper.map(lecture, LectureDTO.class));
        }

        return result;
    }

    /**
     * Gets lectures with the given student.
     *
     * @param student student
     * @return lectures that are attended by student
     * @throws ServiceFailureException if any error occurs.
     */
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_USER')")
    @Transactional(readOnly = true)
    @Override
    public List<LectureDTO> getLectures(StudentDTO student) throws ServiceFailureException {
        if (student == null) {
            throw new IllegalArgumentException("Student is null in LectureServiceImpl.getLectures method");
        }
        Student studentEntity = mapper.map(student, Student.class);

        List<Lecture> lectures = lectureDao.getLectures(studentEntity);
        List<LectureDTO> result = new ArrayList<LectureDTO>();
        for (Lecture lecture : lectures) {
            result.add(mapper.map(lecture, LectureDTO.class));
        }

        return result;
    }

    /**
     * Gets lectures with the given course.
     *
     * @param course course
     * @return lectures that are a part of course
     * @throws ServiceFailureException if any error occurs.
     */
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_USER')")
    @Transactional(readOnly = true)
    @Override
    public List<LectureDTO> getLectures(CourseDTO course) throws ServiceFailureException {
        if (course == null) {
            throw new IllegalArgumentException("Student is null in LectureServiceImpl.getLectures method");
        }
        Course courseEntity = mapper.map(course, Course.class);


        List<Lecture> lectures = lectureDao.getLectures(courseEntity);
        List<LectureDTO> result = new ArrayList<LectureDTO>();
        for (Lecture lecture : lectures) {
            result.add(mapper.map(lecture, LectureDTO.class));
        }

        return result;
    }
}
